
#include <cstdio>
#include "member_BClass.h"
#include "member_BObject.h"

using namespace BWE;

bool BWE::AnalyseDeclare(BString& name, BString& type, ParamInfoArray& params)
{
	name.trimmed();
	if (name.endWith(';'))
	{
		name -= ';';
		name.trimmed();
	}
	name.simplify();
	int pos = name.rfind('(');
	if (name(pos - 1) == ' ')
		name.remove(--pos);
	int end = name.rfind(')');
	if (pos < 0 || end < 0)
		return false;
	BString paramsText;
	name.substr(paramsText, pos + 1, end);
	name.remove(pos, name.size());
	name.trimmed();
	while (pos > 0 && --pos)
	{
		if (name[pos] == ' ')
			break;
		if (name[pos] == '>')
		{
			int head = pos;
			while (head > 0 && name[--head] != '<');
			if (head > 0)
				pos = head;
		}
	}
	if (pos > 0)
	{
		name.substr(type, 0, pos);
		if (type == "void")
			type.clear();
		name.remove(0, pos);
	}
	name.compact();

	name << '(';
	if (paramsText.size())
	{
		BString word;
		int begin = 0;
		int end = 0;
		while (end <= paramsText.size())
		{
			char ch = paramsText[end];
			if (ch == '<')
			{
				while (end < paramsText.size())
					if (paramsText[end++] == '>')
						break;
				continue;
			}
			if (ch == ',' || ch == 0)
			{
				paramsText.substr(word, begin, end);
				begin = ++end;
				ParamInfo& pinfo = params.append();
				AnalyseParam(word, pinfo);
				if (pinfo.cnst)
					name << "const ";
				name << pinfo.type << pinfo.refe << ", ";
				continue;
			}
			end++;
		}
		name -= ", ";
	}
	name << ')';
	return true;
}
bool BWE::AnalyseParam(BString& word, ParamInfo& pinfo)
{
	word.trimmed();
	if (word.beginWith("const "))
	{
		word.remove("const ");
		pinfo.cnst = true;
	}
	int split = bMin(word.find('*'), word.find('&'));
	if (split < word.size())
	{
		pinfo.refe = word[split];
		word.substr(pinfo.type, 0, split);
		word.remove(0, split + 1);
	}
	else
	{
		split = word.find(' ');
		word.substr(pinfo.type, 0, split);
		word.remove(0, split + 1);
	}
	if (word.size())
	{
		int equal = word.find('=');
		if (equal < word.size())
		{
			word.substr(pinfo.name, 0, equal);
			word.remove(0, equal + 1);
			word.trimmed();
		}
		else
		{
			pinfo.name = word;
			word.reset();
		}
	}
	if (word.size())
	{
		if (!CreateValue(word, pinfo))
			return false;
		pinfo.defut = true;
	}
	pinfo.type.compact();
	pinfo.name.compact();
	return true;
}
bool BWE::CreateValue(BString& word, ParamInfo& pinfo)
{
	if (word == "null")
	{
		pinfo.value.clear();
		return true;
	}
	else if (word == "true")
	{
		if (pinfo.type == "bool")
		{
			pinfo.value = true;
			return true;
		}
	}
	else if (word == "false")
	{
		if (pinfo.type == "bool")
		{
			pinfo.value = false;
			return true;
		}
	}
	else if (word[0] == '\"')
	{
		word.remove(0);
		if (!word.endWith('\"'))
		{
			puts("Error : string is not finished.");
			return false;
		}
		word -= '\"';
		word.replace("\\n", '\n');
		word.replace("\\t", '\t');
		word.replace("\\r", '\r');
		if (pinfo.type == "string")
		{
			pinfo.value = word;
			return true;
		}
	}
	else if (word[0] == '\'')
	{
		word.remove(0);
		if (word.endWith('\''))
		{
			puts("Error : string is not finished.");
			return false;
		}
		word -= '\'';
		word.replace("\\n", '\n');
		word.replace("\\t", '\t');
		word.replace("\\r", '\r');
		if (word.size() > 1)
		{

		}
		if (pinfo.type == "string")
		{
			pinfo.value = word;
			return true;
		}
		if (pinfo.type == "char")
		{
			pinfo.value = (char)word(0);
			return true;
		}
		if (pinfo.type == "byte")
		{
			pinfo.value = (BByte)word(0);
			return true;
		}
	}
	else if (word.isNumber())
	{
		if (pinfo.type == "auto")
		{
			if (word == "false")
			{
				pinfo.value = false;
				return true;
			}
			if (word == "true")
			{
				pinfo.value = true;
				return true;
			}
			if (word.contain('e'))
			{
				if (word.endWith('f'))
					pinfo.value = strtof(word.cstr(), 0);
				else
					pinfo.value = strtod(word.cstr(), 0);
				return true;
			}
			if (word.contain('.'))
			{
				if (word.endWith('f'))
					pinfo.value = word.toFloat();
				else
					pinfo.value = word.toDouble();
				return true;
			}
			pinfo.value = word.toInt();
			return true;
		}
		if (pinfo.type == "int")
		{
			pinfo.value = word.toInt();
			return true;
		}
		else if (pinfo.type == "char")
		{
			pinfo.value = (char)word.toInt();
			return true;
		}
		else if (pinfo.type == "byte")
		{
			pinfo.value = (BByte)word.toInt();
			return true;
		}
		else if (pinfo.type == "short")
		{
			pinfo.value = (short)word.toInt();
			return true;
		}
		else if (pinfo.type == "long")
		{
			pinfo.value = word.toLong();
			return true;
		}
		else if (pinfo.type == "real")
		{
			pinfo.value = word.toReal();
			return true;
		}
		else if (pinfo.type == "float")
		{
			pinfo.value = word.toFloat();
			return true;
		}
		else if (pinfo.type == "double")
		{
			pinfo.value = word.toDouble();
			return true;
		}
	}
	printf("Error : param assign type %s with bad value [%s].", pinfo.type.cstr(), word.cstr());
	return false;
}
bool BWE::ValueString(BString& text, const BValue& value)
{
	text << " = ";
	if (value.empty())
	{
		text << "null";
	}
	else if (value.is<bool>())
	{
		bool b = value;
		text << (b ? "true" : "false");
	}
	else if (value.is<char>())
	{
		char c = value;
		text << '\'' << (int)c << '\'';
	}
	else if (value.is<BByte>())
	{
		BByte b = value;
		text << (int)b;
	}
	else if (value.is<short>())
	{
		short s = value;
		text << (int)s;
	}
	else if (value.is<int>())
	{
		int i = value;
		text << i;
	}
	else if (value.is<BLong>())
	{
		BLong l = value;
		text << l;
	}
	else if (value.is<float>())
	{
		float f = value;
		text << f << 'f';
	}
	else if (value.is<double>())
	{
		double d = value;
		text << d;
	}
	else if (value.is<BString>())
	{
		const BString& str = value;
		text << '\"' << str << '\"';
	}
	else
	{
		return false;
	}
	return true;
}

member_BClass::member_BClass(BClass* cls)
{
	boss = cls;
	script = 0;
	ismeta = false;
}
member_BClass::~member_BClass()
{

}

bool member_BClass::instantiate(const BString& name)
{
	const BString& baseName = boss->name();
	BStringArray types;
	int begin = name.find('<') + 1;
	int stop = name.find('>');
	int end = begin;
	while (end <= stop)
	{
		char ch = name[end];
		if (ch == '<')
		{
			while (end < stop)
				if (name[end++] == '>')
					break;
			continue;
		}
		if (ch == ',' || ch == '>')
		{
			BString& word = types.append();
			name.substr(word, begin, end);
			begin = ++end;
			continue;
		}
		end++;
	}

	if (types.size() != tempTypes.size())
		return false;

	BString str;
	for (int i = 0; i < tempTypes.size(); i++)
	{
		BString& temp = tempTypes[i];
		BString& type = types[i];
		for (int i = 0; i < variants.size(); i++)
		{
			VariantInfo& vinfo = variants[i];
			str.reset();
			str << vinfo.type;
			str.replace(temp, type);
			vinfo.type = str;
		}
		for (auto it = methodMap.begin(); it.valid(); ++it)
		{
			BString& methodName = it.key();
			methodName.replace(temp, type);
			MethodInfo* minfo = *it;
			minfo->type.replace(temp, type);
			for (int i = 0; i < minfo->params.size(); i++)
			{
				ParamInfo& pinfo = minfo->params[i];
				str.reset();
				str << pinfo.type;
				str.replace(temp, type);
				pinfo.type = str;
			}
		}
		temp = type;
	}
	methodMap.resort();
	object_member(boss)->name = name;
	return true;
}
bool member_BClass::checkInherit(const BString& type)
{
	if (type.endWith('&') || type.endWith('*') || type.beginWith("const "))
	{
		BString temp = type;
		if (type.endWith('&'))
			temp -= '&';
		if (type.endWith('*'))
			temp -= '*';
		if (type.beginWith("const "))
			temp.remove("const ");
		for (int i = 0; i < inherits.size(); i++)
		{
			if (inherits[i]->type == temp)
				return true;
		}
		return false;
	}
	for (int i = 0; i < inherits.size(); i++)
	{
		if (inherits[i]->type == type)
			return true;
	}
	return false;
}
VariantInfo* member_BClass::findVariant(const BString& name)
{
	int index = variants.find(name);
	if (index < variants.size())
	{
		VariantInfo& vinfo = variants[index];
		return &vinfo;
	}
	if (BExp* exp = inherits.first())
	{
		if (BClass* cls = exp->value)
		{
			return class_member(cls)->findVariant(name);
		}
	}
	return 0;
}
BValue* member_BClass::findValue(const BString& path)
{
	int pos = path.find('.');
	if (pos < path.size())
	{
		BString name;
		path.substr(name, 0, pos);
		int index = variants.find(name);
		if (index == variants.size())
			return 0;
		BValue* ptr = &(variants[index].value);
		while (pos < path.size())
		{
			pos = path.word(name, pos);
			if (name == '.')
				continue;
			BClass* obj = *ptr;
			if (!obj)
				return 0;
			int index = class_member(obj)->variants.find(name);
			if (index == class_member(obj)->variants.size())
				return 0;
			VariantInfo& vinfo = class_member(obj)->variants[index];
			ptr = &(vinfo.value);
		}
		return ptr;
	}
	int index = variants.find(path);
	if (index == variants.size())
		return 0;
	BValue* ptr = &(variants[index].value);
	return ptr;
}

